package com.vains.config.security;

import com.vains.config.bean.CustomerRemoteTokenServices;
import com.vains.enumeration.ResultEnum;
import com.vains.exception.AuthExceptionEntryPoint;
import com.vains.io.JsonUtils;
import com.vains.system.model.Result;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@Configuration
@AllArgsConstructor
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private final AuthExceptionEntryPoint authExceptionEntryPoint;

    private final CustomerRemoteTokenServices customerRemoteTokenServices;

    private final OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 认证服务器请求放行
        http.authorizeRequests().antMatchers("/auth/**").permitAll();
        // 关闭basic认证
        // http.httpBasic().disable();
        // 任何请求都要先经过认证
        http.authorizeRequests().anyRequest().access("@authServiceImpl.hasAuth()");
        http.exceptionHandling()
            .authenticationEntryPoint(this::authenticationDeniedHandler)
            .accessDeniedHandler(this::accessDeniedHandler);
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        // 设置当前资源ID
        resources.resourceId("zuul");
        resources.tokenServices(customerRemoteTokenServices);
        resources.expressionHandler(oAuth2WebSecurityExpressionHandler);
        resources.authenticationEntryPoint(authExceptionEntryPoint);
    }

    private void accessDeniedHandler(HttpServletRequest request, HttpServletResponse response, AccessDeniedException authException) {
        response.setContentType("application/json; charset=utf-8");
        Result<String> result = new Result<>(ResultEnum.NO_PERMISSION.getCode(), false, ResultEnum.NO_PERMISSION.getMessage(), null);
        try {
            response.getWriter().println(JsonUtils.objectCovertToJson(result));
        } catch (IOException e) {
            log.error("无权限提醒时响应失败! 原因: ", e);
        }
    }

    private void authenticationDeniedHandler(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
        response.setContentType("application/json; charset=utf-8");
        Result<String> result = new Result<>(ResultEnum.NO_LOGIN.getCode(), false, ResultEnum.NO_LOGIN.getMessage(), null);
        try {
            response.getWriter().println(JsonUtils.objectCovertToJson(result));
        } catch (IOException e) {
            log.error("无权限提醒时响应失败! 原因: ", e);
        }
    }

}